package com.toolkit.util;

import com.aliyun.oss.HttpMethod;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.*;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;


@Component
@Slf4j
public final class OSSUtils {
    private static final Logger LOGGER = LoggerFactory.getLogger(OSSUtils.class);

    private static OSS ossClient;

    @Autowired
    public  void setOssClient(OSS clients) {
        ossClient=clients;
    }

    private static OSSClient publicOssClient;
    
    
    private static String readEndpoint;
    
    private static String endpoint;
    
    private static String bucketName;

    @Value("${oss.bucketName}")
    public void setBucketName(String bucketName) {
        OSSUtils.bucketName = bucketName;
    }
    
    @Value("${oss.readEndpoint}")
    public void setReadEndpoint(String readEndpoint) {
        OSSUtils.readEndpoint = readEndpoint;
    }

    @Value("${oss.endpoint}")
    public void setEndpoint(String endpoint) {
        OSSUtils.endpoint = endpoint;
    }


    
    public void setPublicOssClient(OSSClient publicOssClient) {
        OSSUtils.publicOssClient = publicOssClient;
    }



    /**
     * 上传文件到bucket下的指定key
     *
     * @param bucketName bucket名称
     * @param key        文件key
     * @param file       本地文件
     */
    public static void uploadFile(String bucketName, String key, File file) {
        ossClient.putObject(bucketName, key, file);
    }
    
    /**
     * 上传文件到bucket下的指定key
     *
     * @param bucketName bucket名称
     * @param key        文件key
     * @param file       本地文件
     */
    public static void uploadFileToPublic(String bucketName, String key, File file) {
        publicOssClient.putObject(bucketName, key, file);
    }

    /**
     * 上传文件到bucket下的指定key
     *
     * @param bucketName   bucket名称
     * @param key          文件key
     * @param fileContent  本地文件
     * @param fileMetadata 文件元数据信息
     */
    public static void uploadFileToPublic(String bucketName, String key, InputStream fileContent, ObjectMetadata fileMetadata) {
        publicOssClient.putObject(bucketName, key, fileContent, fileMetadata);
    }

    /**
     * 上传文件到bucket下的指定key
     *
     * @param bucketName   bucket名称
     * @param key          文件key
     * @param fileContent  本地文件
     * @param fileMetadata 文件元数据信息
     */
    public static void uploadFile(String bucketName, String key, InputStream fileContent, ObjectMetadata fileMetadata) {
        ossClient.putObject(bucketName, key, fileContent, fileMetadata);
    }

    /**
     * 上传文件到bucket下的指定key
     *
     * @param bucketName   bucket名称
     * @param key          文件key
     * @param file         本地文件
     * @param fileMetadata 文件元数据信息
     */
    public static void uploadFile(String bucketName, String key, File file, Map<String, String> fileMetadata) {
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setUserMetadata(fileMetadata);
        ossClient.putObject(bucketName, key, file, metadata);
    }

    /**
     * 上传文件到bucket下指定key
     *
     * @param bucketName  bucket名称
     * @param key         文件key
     * @param fileContent 文件内容流
     * @throws IOException 可能发生的IO异常
     */
    public static void uploadFile(String bucketName, String key, InputStream fileContent) throws IOException {
        log.info("上传文件的bucketName:{},key:{}",bucketName,key);
        ossClient.putObject(bucketName, key, fileContent);
    }

    /**
     * 上传文件到bucket下指定key
     * @param key         文件key
     * @param fileContent 文件内容流
     * @throws IOException 可能发生的IO异常
     */
    public static String uploadFile(String key, InputStream fileContent) throws IOException {
        log.info("上传文件的bucketName:{},key:{}", bucketName, key);
        ossClient.putObject(bucketName, key, fileContent);
        return readEndpoint + File.separator + bucketName + File.separator + key;
    }

    /**
     * 上传文件到bucket下指定key
     *
     * @param bucketName   bucket名称
     * @param key          文件key
     * @param fileContent  文件内容流
     * @param fileMetadata 文件元数据信息
     * @throws IOException 可能发生的IO异常
     */
    public static void uploadFile(String bucketName, String key, InputStream fileContent, Map<String, String> fileMetadata) throws IOException {
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setUserMetadata(fileMetadata);
        metadata.setContentType("application/octet-stream");
        metadata.setContentDisposition("attachment; filename="+fileMetadata.get("myFileName"));
        ossClient.putObject(bucketName, key, fileContent, metadata);
    }
    
    /**
     * 上传文件到bucket下指定key
     *
     * @param bucketName   bucket名称
     * @param key          文件key
     * @param fileContent  文件内容流
     * @param fileMetadata 文件元数据信息
     * @throws IOException 可能发生的IO异常
     */
    public static void uploadFileToPublic(String bucketName, String key, InputStream fileContent, Map<String, String> fileMetadata) throws IOException {
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setUserMetadata(fileMetadata);
        metadata.setContentType("application/octet-stream");
        metadata.setContentDisposition("attachment; filename="+fileMetadata.get("myFileName"));
        publicOssClient.putObject(bucketName, key, fileContent, metadata);
    }

    /**
     * 将源bucket下的指定key对应的文件复制到目标bucket下的指定key
     *
     * @param sourceBucketName      源bucket名称
     * @param sourceKey             源文件key
     * @param destinationBucketName 目标bucket名称
     * @param destinationKey        目标文件key
     */
    public static void copyFile(String sourceBucketName, String sourceKey, String destinationBucketName, String destinationKey) {
        ossClient.copyObject(sourceBucketName, sourceKey, destinationBucketName, destinationKey);
    }
    
    /**
     * 将源bucket下的指定key对应的文件复制到目标bucket下的指定key
     *
     * @param sourceBucketName      源bucket名称
     * @param sourceKey             源文件key
     * @param destinationBucketName 目标bucket名称
     * @param destinationKey        目标文件key
     */
    public static void copyPublicFile(String sourceBucketName, String sourceKey, String destinationBucketName, String destinationKey) {
        publicOssClient.copyObject(sourceBucketName, sourceKey, destinationBucketName, destinationKey);
    }

    /**
     * 获取oss文件内容流
     *
     * @param bucketName bucket名称
     * @param key        文件key
     */
    public static InputStream getFileContent(String bucketName, String key) {
        OSSObject object = ossClient.getObject(bucketName, key);
        return object.getObjectContent();
    }

   /* *//**
     * 获取oss文件对象
     *
     * @param bucketName bucket名称
     * @param key        文件key
     *//*
    public static GetFileResult getFileObject(String bucketName, String key) {
        OSSObject object = ossClient.getObject(bucketName, key);
        InputStream fileContent = object.getObjectContent();
        Map<String, String> fileMetadata = object.getObjectMetadata().getUserMetadata();
        return new GetFileResult(fileContent, fileMetadata);
    }*/

    /**
     * 删除指定bucket下的文件key
     *
     * @param bucketName bucket名称
     * @param key        文件key
     */
    public static void deleteFile(String bucketName, String key) {
        ossClient.deleteObject(bucketName, key);
    }
    
    /**
     * 删除指定bucket下的文件key
     *
     * @param bucketName bucket名称
     * @param key        文件key
     */
    public static void deletePublicFile(String bucketName, String key) {
        publicOssClient.deleteObject(bucketName, key);
    }


    public static String generatePresignedUrl(String key) {
        Calendar cal=Calendar.getInstance();
        Date expiration = new Date();
        cal.setTime(expiration);
        cal.add(Calendar.YEAR, 100);
        expiration = cal.getTime();
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, key, HttpMethod.GET);
        //设置过期时间
        request.setExpiration(expiration);
        // 生成URL签名(HTTP GET请求)
        URL signedUrl = ossClient.generatePresignedUrl(request); 
        //LOGGER.info("bucketName【{}】, key【{}】, signedUrl【{}】",bucketName, key, signedUrl.toString());
        System.out.println("signedUrl:"+signedUrl);
        String realUrl = signedUrl.toString();
        System.out.println("realUrl:"+realUrl);
        System.out.println("endpoint:"+endpoint);
        System.out.println("readEndpoint:"+readEndpoint);
        String visitleUrll = realUrl.replaceAll(endpoint, readEndpoint);
        System.out.println("visitleUrll:"+visitleUrll);
        return visitleUrll;
    }

    /**
     * 下载文件带签名的
     * @param key
     * @return
     */
    public static String generatePresignedDownloadUrl(String key, String fileName) {
        Calendar cal=Calendar.getInstance();
        Date expiration = new Date();
        cal.setTime(expiration);
        //后一天
        cal.add(Calendar.HOUR, 1);
        expiration = cal.getTime();
//        key = key + "?response-content-disposition=attachment;filename=" + fileName + ";filename*=UTF-8''" +  fileName;
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, key, HttpMethod.GET);

        ResponseHeaderOverrides responseHeaders = new ResponseHeaderOverrides();
        responseHeaders.setContentDisposition("attachment;filename=" + fileName + ";filename*=UTF-8''" +  fileName);
        request.setResponseHeaders(responseHeaders);

        //设置过期时间Dis
        request.setExpiration(expiration);
        // 生成URL签名(HTTP GET请求)
        URL signedUrl = ossClient.generatePresignedUrl(request);
        String realUrl = signedUrl.toString();
        LOGGER.info("bucketName【{}】, key【{}】, signedUrl【{}】",bucketName, key, realUrl);

        String visitleUrll = realUrl.replace(endpoint, readEndpoint);
//        try {
//            //+ "&response-content-disposition=attachment%3Bfilename=" + fileName + "%3Bfilename*%3DUTF-8''" + fileName
//            visitleUrll = URLEncoder.encode(visitleUrll, "UTF-8");
//        } catch (UnsupportedEncodingException e) {
//            e.printStackTrace();
//        }
        LOGGER.info("URLDecoder.decode=" + visitleUrll);
        return visitleUrll;
    }

    public static String generatePresignedUrl(String key, int hour) {
        Calendar cal=Calendar.getInstance();
        Date expiration = new Date();
        cal.setTime(expiration);
        //后一天
        cal.add(Calendar.HOUR, hour);
        expiration = cal.getTime();
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, key, HttpMethod.GET);
        //设置过期时间
        request.setExpiration(expiration);
        // 生成URL签名(HTTP GET请求)
        URL signedUrl = ossClient.generatePresignedUrl(request);
        //LOGGER.info("bucketName【{}】, key【{}】, signedUrl【{}】",bucketName, key, signedUrl.toString());

        String realUrl = signedUrl.toString();

        String visitleUrll = realUrl.replace(endpoint, readEndpoint);

        return visitleUrll;
    }

    public String upload(String path,InputStream inputStream){
        try {

                OSSUtils.uploadFile(bucketName, path, inputStream);
//            return "http://" + bucketName + "." + endpoint + "/" + path + "/" + fileName;
            } catch (IOException e) {
                log.info("[上传失败] "+ e.getMessage());
            }

            return null;
    }

    /**
     * 上传文件到bucket下指定key
     * @param key         文件key
     * @param fileContent 文件内容流
     * @throws IOException 可能发生的IO异常
     */
    public static String uploadFileReturnPath(String key, InputStream fileContent) throws IOException {
        log.info("上传文件的bucketName:{},key:{}", bucketName, key);
        ossClient.putObject(bucketName, key, fileContent);
        return readEndpoint + File.separator + bucketName + File.separator + key;
    }

    /**
     * 获取oss文件对象
     *
     * @param bucketName bucket名称
     * @param key        文件key
     */
    public static GetFileResult getFileObject(String bucketName, String key) {
        OSSObject object = ossClient.getObject(bucketName, key);
        InputStream fileContent = object.getObjectContent();
        Map<String, String> fileMetadata = object.getObjectMetadata().getUserMetadata();
        return new GetFileResult(fileContent, fileMetadata);
    }
    public InputStream download(String path) {
        GetFileResult fileResult = OSSUtils.getFileObject(bucketName, path);
        log.info("path:{},fileResult:{},bucketName:{}",path,fileResult,bucketName);
        return fileResult.getFileContent();
    }

    /**
     * 下载文件到本地
     * @param key
     * @param filePath
     */
    public void downloadFile(String key, String filePath){
        ossClient.getObject(new GetObjectRequest(bucketName, key), new File(filePath));
    }

    /**
     * oss地址下载文件到本地
     * @param ossPath
     * @param downloadFilePath
     */
    public void downloadOssFile(String ossPath, String downloadFilePath){
        String key = ossPath.replace(readEndpoint + File.separator + bucketName + File.separator, "");
        downloadFile(key, downloadFilePath);
    }




}
